package y.q.h.common;


import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import y.q.h.util.apicontroller.R;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static y.q.h.util.apicontroller.R.failed;


/**
 * 公共处理类
 *
 * @author SongRenShuo
 * @date 2023/12/14
 */
@Slf4j
@CrossOrigin // 跨域
@RestController
@ControllerAdvice
public class CommonController {

    /**
     * 异常处理程序
     *
     * @param e e
     * @return {@link R }
     * @date 2024/04/04
     * @author SongRenShuo
     */
    @ExceptionHandler
    public R exceptionHandler(Exception e) {

        if (e instanceof HttpRequestMethodNotSupportedException) {
            log.error("请求方式错误：", e);
            return failed("请求方式错误：" + e.getMessage());
        } else if (e instanceof BindException) {
            log.error("请求参数格式有误：", e);
            List<ObjectError> objectErrorList = ((BindException) e).getAllErrors();
            List<String> errorMessageList = new ArrayList<>();
            if (!CollectionUtils.isEmpty(objectErrorList)) {
                // 错误非空
                for (ObjectError error : objectErrorList) {
                    errorMessageList.add(error.getDefaultMessage());
                }
            }
            return failed("请求参数格式有误：" + errorMessageList);
        } else if (e instanceof MethodArgumentTypeMismatchException) {
            log.error("请求参数类型不匹配：", e);
            MethodArgumentTypeMismatchException mismatchException = (MethodArgumentTypeMismatchException) e;
            return failed("请求参数类型不匹配：无法将值 " + mismatchException.getValue() + " 转换为类型 " + Objects.requireNonNull(mismatchException.getRequiredType()).getSimpleName());
        }
        // 如果是HttpMessageNotReadableException，也可能是由于日期转换失败导致的
        else if (e instanceof HttpMessageNotReadableException && e.getCause() instanceof MethodArgumentTypeMismatchException) {
            MethodArgumentTypeMismatchException nestedException = (MethodArgumentTypeMismatchException) e.getCause();
            log.error("请求参数类型不匹配（嵌套）：", nestedException);
            return failed("请求参数类型不匹配（嵌套）：无法将值 " + nestedException.getValue() + " 转换为类型 " + Objects.requireNonNull(nestedException.getRequiredType()).getSimpleName());
        } else if (e instanceof ConstraintViolationException) {
            // 校验框架 - violation
            StringBuilder errorMessage = new StringBuilder("请求参数错误：");
            Set<ConstraintViolation<?>> violations = ((ConstraintViolationException) e).getConstraintViolations();
            for (ConstraintViolation<?> violation : violations) {
                String messageTemplate = violation.getMessageTemplate();
                // // 大多数情况下错误信息会包含冒号分隔的字段名和错误描述
                if (messageTemplate.contains(":")) {
                    errorMessage.append(violation.getMessage().split(":")[1].trim()).append(", ");
                } else {
                    errorMessage.append(violation.getMessage()).append(" ");
                }
            }
            // 去除最后一个逗号和空格
            errorMessage.setLength(errorMessage.length());
            log.error(errorMessage.toString());
            return failed(errorMessage.toString());
        }
        log.error("公共类异常：", e);
        return failed("公共类异常：" + e.getMessage());
    }

}
